﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Automation;
using System.Drawing;
using System.Diagnostics;
using System.Threading;
using System.Text.RegularExpressions;
using Dtf.Core.Remoting;
using Dtf.Core.Controls;
using Dtf.Core.Utilities;

namespace Dtf.Core
{

    public class UIItem : RemotingObject
    {
        private AutomationElement _element = null;

        //private AutomationEventHandler _globEventHandler;

        //private event UIEventHandler UIEvent;

        
        

        #region Constructor

        public UIItem(UIItem item)
        {
            _element = item._element;
        }
        
        public UIItem(string queryString)
        {

            UICollection<UIItem> tree = new UICollection<UIItem>(UIItem.Root, UIScope.Descendants);
            
            UIItem item = tree.FindFirst(queryString);

            _element = item.Element;
 
        }


        internal UIItem(AutomationElement element)
        {
            if (element == null)
            {
                throw new ArgumentNullException("AutomationElement is null!");
            }
            _element = element;
        }


        public UIItem(IntPtr hWnd)
        {
            _element = AutomationElement.FromHandle(hWnd);
        }

        public UIItem(int xPos, int yPos)
        {
            _element = AutomationElement.FromPoint(new System.Windows.Point(xPos, yPos));
        }


        #endregion



        #region pub method


        //public void AddUIEventHandler(UIEventType eventType, UIScope scope, UIEventHandler handler)
        //{
        //    if (_globEventHandler == null)
        //    {
        //        _globEventHandler = new AutomationEventHandler(OnUIAEvent);
        //    }
        //    AutomationEvent uiaEvent;
        //    switch (eventType)
        //    {
        //        case UIEventType.MenuClosedEvent:
        //            uiaEvent = AutomationElement.MenuOpenedEvent;
        //            break;
        //        case UIEventType.MenuOpenedEvent:
        //            uiaEvent = AutomationElement.MenuClosedEvent;
        //            break;
                

        //    }
        //    Automation.AddAutomationEventHandler(AutomationElement.MenuOpenedEvent, AutomationElement.RootElement, TreeScope.Descendants, OnUIAEvent);
        //    UIEvent += new UIEventHandler(handler);
        //}

        //private void OnUIAEvent(object sender, AutomationEventArgs args)
        //{
        //    AutomationElement element = (AutomationElement)sender;
        //    UIEventType eventType = UIEventType.MenuOpenedEvent;
        //    AutomationEvent eventId = args.EventId;
        //    if (eventId == AutomationElement.MenuOpenedEvent)
        //    {
        //        eventType = UIEventType.MenuOpenedEvent;
        //    }
        //    UIEventArgs eventArgs = new UIEventArgs(eventType);
        //    UIEvent.Invoke(new UIItem(element), eventArgs);
        //}

        public void BringToFront()
        {
            AutomationElement el = Element;

            AutomationElement mainElement = el;
            while (el != AutomationElement.RootElement)
            {
                mainElement = el;
                el = TreeWalker.RawViewWalker.GetParent(el);
            }


            IntPtr hMainWnd = new IntPtr(mainElement.Current.NativeWindowHandle);

            NativeMethods.SendMessage(hMainWnd, 0x0112, 0xF120, 0);
            NativeMethods.SetForegroundWindow(hMainWnd);

        }

        public void Click()
        {
            Click(MouseButton.Left);
        }

        public void Click(MouseButton button)
        {
            this.BringToFront();

            try
            {
                int x = (int)Element.Current.BoundingRectangle.X;
                int y = (int)Element.Current.BoundingRectangle.Y;
                System.Windows.Point p = Element.GetClickablePoint();
                p.X -= x;
                p.Y -= y;

                Click(button, (int)p.X, (int)p.Y);
            }
            catch (NoClickablePointException)
            {
                LogManager.Write("Error: UI is No Clickable@UIItem::Click.\n", "red");
                return;
            }
        }

        public void Click(MouseButton button, int offsetX, int offsetY)
        {
            this.BringToFront();
            Mouse.Move((int)Element.Current.BoundingRectangle.X + offsetX, (int)Element.Current.BoundingRectangle.Y + offsetY);

            Mouse.Click(button);

        }


        public void DragTo(MouseButton button, UIItem target)
        {
            throw new NotImplementedException();
        }

        public void MovePointer()
        {
            Mouse.Move((int)Element.Current.BoundingRectangle.X, (int)Element.Current.BoundingRectangle.Y);
        }

        public void MovePointer(int offsetX, int offsetY)
        {
            Mouse.Move(offsetX, offsetY);
        }

        public void SendKeys(string text)
        {
            this.SetFocus();
            Keyboard.SendKeys(text);
        }

        public void SetFocus()
        {
            this.BringToFront();
        }

        public void Hightlight()
        {
            Highlighter lighter = new Highlighter();
            lighter.SetLocation(this.BoundingRectangle);
            lighter.Show();
        }

        public Image GetImage()
        {
            Image img = ScreenCapture.GetImage(this.BoundingRectangle.X, this.BoundingRectangle.Y, this.BoundingRectangle.Width, this.BoundingRectangle.Height);
            return null;
        }

        public void SaveImage(string filename)
        {
            GetImage().Save(filename);
        }

        public object GetPropertyValue(UIProperty property)
        {
            AutomationProperty uiaProp = property.AutomationProperty;
            return _element.GetCurrentPropertyValue(uiaProp, false);
        }

        /// <summary>
        /// if this and the given object correspond to the same UI.
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        public override bool Equals(object obj)
        {
            UIItem item = obj as UIItem;
            return this == item;
        }

        public bool Equals(UIItem item)
        {
            return this == item;
        }

        public static bool operator ==(UIItem a, UIItem b)
        {
            object obj1 = a;
            object obj2 = b;
            if (obj1 == null || obj2 == null)
            {
                if (obj1 == null && obj2 == null)
                {
                    return true;
                }
                return false;
            }
            return Automation.Compare(a._element, b._element);
        }

        public static bool operator !=(UIItem a, UIItem b)
        {
            return !(a == b);
        }

        public override int GetHashCode()
        {
            int[] runtimeId = this.Element.GetRuntimeId();
            int hash = 0;
            foreach (int component in runtimeId)
            {
                hash = hash ^ component;
            }
            return hash;
        }

        #endregion


        /// <summary>
        /// Root (Desktop)
        /// </summary>
        public static UIItem Root
        {
            get
            {
                UIItem item = new UIItem(AutomationElement.RootElement);
                return item;
            }
        }

        internal AutomationElement.AutomationElementInformation Current
        {
            get
            {
                return Element.Current;
            }
        }

        #region UI Propertys

        public UIProperty[] SupportedProperties
        {
            get
            {
                List<UIProperty> propertyNames = new List<UIProperty>();
                AutomationProperty[] properties = _element.GetSupportedProperties();
                foreach (AutomationProperty property in properties)
                {
                    propertyNames.Add(UIProperty.Get(property));
                }
                return propertyNames.ToArray();
            }
        }

        internal AutomationElement Element
        {
            get
            {
                return _element;
            }
        }

        public UIItem FirstChild
        {
            get
            {
                AutomationElement el = TreeWalker.ControlViewWalker.GetFirstChild(_element);
                if (el == null)
                {
                    return null;
                }
                return new UIItem(el);
            }
        }

        #region AutomationProperty
        public string Name
        {
            get
            {
                return Element.Current.Name;
            }
        }

        public string ClassName
        {
            get
            {
                return Element.Current.ClassName;
            }
        }

        public int ProcessId
        {
            get
            {
                return Element.Current.ProcessId;
            }
        }

        public int[] RuntimeId
        {
            get
            {
                return Element.GetRuntimeId();
            }
        }
        #endregion

        public UIItem Parent
        {
            get
            {
                AutomationElement el = TreeWalker.RawViewWalker.GetParent(_element);
                if (el == null)
                {
                    return null;
                }
                return new UIItem(el);
            }
        }

        public UICollection<UIItem> Children
        {
            get
            {
                return new UICollection<UIItem>(this, UIScope.Children);
            }
        }

        public UICollection<UIItem> Descendants
        {
            get
            {
                return new UICollection<UIItem>(this, UIScope.Descendants);
            }
        }

        public UIItem NextSibling
        {
            get
            {
                //MS.Internal.Mita.Foundation.UIObject o = MS.Internal.Mita.Foundation.UIObject.Factory.Create(_element);
                //if (o == null)
                //{
                //    return null;
                //}
                //o = o.NextSibling;
                //if (o == null)
                //{
                //    return null;
                //}
                // AutomationElement el = o.AutomationElement;
                //AutomationElement el = new TreeWalker(Automation.ControlViewCondition).GetNextSibling(_element);
                AutomationElement el = TreeWalker.ControlViewWalker.GetNextSibling(_element);
                if (el == null)
                {
                    return null;
                }
                return new UIItem(el);
            }
        }

        public UIItem PreviousSibling
        {
            get
            {
                AutomationElement el = TreeWalker.ControlViewWalker.GetPreviousSibling(_element);
                if (el == null)
                {
                    return null;
                }
                return new UIItem(el);
            }
        }


        public System.Drawing.Rectangle BoundingRectangle
        {
            get
            {
                return new System.Drawing.Rectangle((int)Element.Current.BoundingRectangle.X, (int)Element.Current.BoundingRectangle.Y, (int)Element.Current.BoundingRectangle.Width, (int)Element.Current.BoundingRectangle.Height);
            }
        }


        #endregion Properties



    }
}